package uk.co.q3c.deplan.client.service;

import java.util.List;

import uk.co.q3c.deplan.client.dao.CalendarService;
import uk.co.q3c.deplan.client.dao.DesignService;
import uk.co.q3c.deplan.client.dao.ResourceService;
import uk.co.q3c.deplan.client.domain.DomainKind;
import uk.co.q3c.deplan.client.domain.DomainObject;
import uk.co.q3c.deplan.client.domain.dag.ChangeInvalidException;
import uk.co.q3c.deplan.client.domain.dag.CycleDetectedException;
import uk.co.q3c.deplan.client.domain.dag.DAG;
import uk.co.q3c.deplan.client.domain.dag.Hierarchy;
import uk.co.q3c.deplan.client.domain.resource.PersistenceReferenceException;
import uk.co.q3c.deplan.client.domain.task.BaseTask;
import uk.co.q3c.deplan.client.domain.task.Task;
import uk.co.q3c.deplan.server.dao.DomainDao_BigT;
import uk.co.q3c.deplan.server.service.TaskService_BigT;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import com.googlecode.objectify.Key;

/**
 * @see TaskServiceAsync
 * @see TaskService_BigT
 * @see ResourceService
 * @see CalendarService
 * @see DesignService
 * @see DomainService
 * @author DSowerby 25 Sep 2008
 * 
 */
@RemoteServiceRelativePath("task")
public interface TaskService extends RemoteService {

	int countPlanManagers();

	int countProjects();

	int countAbstractTasks();

	/**
	 * Finds a task with the given id - this is relatively slow, because it has to check each Task class in turn. Faster if you can identify
	 * the task class and use {@link #findById(Class, long)} instead
	 * 
	 * @see TaskService_BigT#findById(long)
	 * @param id
	 * @return
	 */
	Task findById(long id);

	/**
	 * Finds a task with the given id - a quicker alternative to using {@link #findById(long)}, as the Entity kind is already specified.
	 * 
	 * @see TaskService_BigT#findById(Class, long)
	 * @param id
	 * @return
	 */
	Task findById(DomainKind domainKind, long id);

	Task findFirstByName(List<Class<? extends DomainObject>> taskClasses, String name);

	// the following may be repeated in each of the service interfaces, to allow
	// access to some of the un-typecast methods

	<T extends Task> Key<T> keyFor(T domainObject);

	/**
	 * Sets the domain object's discarded flag to true and saves it. If you don't want to save it automatically, set the discarded flag
	 * directly on the domain object
	 * 
	 * @param dob
	 */
	void discard(DomainObject dob) throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException;

	/**
	 * <b>NOTE</b> This assumes that domainObject has no parent entity. Returns null if domainObject is null
	 * 
	 * @see DomainDao_BigT#keyFor(DomainObject)
	 * @param domainObject
	 *            the object you want the key for
	 * @return
	 */
	<T extends DomainObject> T getObjectFromKey(Key<T> key);

	/**
	 * Forces a new datastore instance (@link Objectify) to be created.
	 */
	void closeSession();

	/**
	 * @see TaskService_BigT#save(DomainObject))
	 * @param dob
	 */
	void save(DomainObject dob);

	// List<DAGChange> saveDependencies();

	/**
	 * @see TaskService_BigT#getDag()
	 * @return
	 */
	DAG<Key<? extends Task>> getDag();

	/**
	 * @see TaskService_BigT#save(DAG)
	 * @param task
	 */
	void save(Task task);

	List<Task> successorsOf(Task abstractTask) throws PersistenceReferenceException;

	/**
	 * @see TaskService_BigT#subTasksOf(BaseTask)
	 * @param summaryTask
	 * @return
	 * @throws PersistenceReferenceException
	 */
	List<? extends Task> subTasksOf(BaseTask summaryTask) throws PersistenceReferenceException;

	BaseTask parentOf(Task task) throws PersistenceReferenceException;

	// List<DAGChange> saveHierarchy();

	void setHierarchy(Hierarchy<Key<? extends Task>> hierarchy);

	Hierarchy<Key<? extends Task>> getHierarchy();

	int subTaskCountFor(BaseTask summaryTask);

	List<Key<? extends Task>> subTasksKeysFor(BaseTask summaryTask) throws PersistenceReferenceException;

	List<Task> predecessorsOf(Task task) throws PersistenceReferenceException;

	/**
	 * @see TaskService_BigT#childCount(BaseTask)
	 * @param at1
	 * @return
	 * @throws PersistenceReferenceException
	 */
	int childCount(BaseTask task) throws PersistenceReferenceException;

	/**
	 * Pushes down the parent's priority, and rolls up the values needed from subtasks. <code>task</code> is at the top of the tree
	 * structure to be actioned.
	 * 
	 * @see TaskService_BigT#rollup(BaseTask)
	 * @param at1
	 * @throws PersistenceReferenceException
	 * @see TaskService_BigT#rollup(Task)
	 */
	void rollup(Task task) throws PersistenceReferenceException;

	void pushDown(Task task) throws PersistenceReferenceException;

	boolean taskIsAtomic(Task task) throws PersistenceReferenceException;

}